package com.yanqu.client.player;

import com.yanqu.client.message.Decrypt;
import com.yanqu.client.message.Encrypt;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.pb.login.LoginProto;
import com.yanqu.road.server.protocol.AgentProtocol;
import com.yanqu.road.server.protocol.GameProtocol;
import com.yanqu.road.utils.YanQuMessageUtils;
import io.vertx.core.Future;
import io.vertx.core.MultiMap;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpClientOptions;
import io.vertx.core.http.WebSocket;
import io.vertx.core.http.WebSocketConnectOptions;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.WebClient;

public class Player {

    private String host;

    private int port;

    private String openId;

    private int serverId;
    private Vertx vertx;
    private long userId;

    private int wsPort;
    private String wsHost;

    private WebClient httpClient;

    private WebSocket websocketConn;

    public Player(String host, int port, String openId, Vertx vertx, int serverId) {
        this.host = host;
        this.port = port;
        this.openId = openId;
        this.vertx = vertx;
        this.serverId = serverId;
    }


    public Future<Object> gameLogin() {
        this.httpClient = WebClient.create(vertx);
        Promise<JsonObject> webGameLoginPromise = Promise.promise();
        this.webGameLogin(webGameLoginPromise);
        Promise<Object> promise = Promise.promise();
        webGameLoginPromise.future().onSuccess(jsonObject -> {
            String address = jsonObject.getString("address");
            String[] strings = address.split(":");
            this.wsHost = strings[0];
            this.wsPort = Integer.parseInt(strings[1]);
            Future<Object> websocketClient = this.createWebsocketClient();
            websocketClient.onSuccess(h -> {
                promise.complete();
            });
        });
        return promise.future();
    }

    public void webGameLogin(Promise<JsonObject> outPromise) {
        Promise<JsonObject> promise = Promise.promise();
        Future<JsonObject> postWebLogin = this.postWebLogin();
        postWebLogin.onSuccess(jsonObject -> {
            Boolean hasRole = jsonObject.getBoolean("hasRole");
            if (hasRole) {
                outPromise.complete(jsonObject);
            } else {
                promise.complete(jsonObject);
            }
        });
        promise.future().compose(r -> {
            return this.postCreateRole();
        }).onSuccess(r -> {
            this.webGameLogin(outPromise);
        });
    }

    public Future<JsonObject> postWebLogin() {
        Promise<JsonObject> promise = Promise.promise();
        MultiMap form = MultiMap.caseInsensitiveMultiMap();
        form.set("param", String.format("{\"openId\":\"%s\",\"token\":\"\",\"plaformUserId\":\"\",\"plaformUserName\":\"\",\"phonePlatform\":1,\"platform\":\"yq\",\"serverId\":%d,\"country\":\"\",\"language\":\"zh_tw\",\"nickName\":\"\"}", this.openId, this.serverId));
        this.httpClient.post(this.port, this.host, "/Web/login")
                .sendForm(form)
                .onSuccess(response -> {
                    JsonObject bodyAsJsonObject = response.bodyAsJsonObject();
                    this.userId = bodyAsJsonObject.getLong("userId");
                    promise.tryComplete(bodyAsJsonObject);
                });
        return promise.future();
    }

    public Future<JsonObject> postCreateRole() {
        Promise<JsonObject> promise = Promise.promise();
        MultiMap form = MultiMap.caseInsensitiveMultiMap();
        form.set("param", "{\"language\":\"zh_tw\",\"sex\":1}");

        this.httpClient
                .post(this.port, this.host, "/Web/getRandomName")
                .sendForm(form)
                .compose(response -> {
                    JsonObject bodyAsJsonObject = response.bodyAsJsonObject();
                    String nickname = bodyAsJsonObject.getString("name");
                    MultiMap createRoleForm = MultiMap.caseInsensitiveMultiMap();
                    createRoleForm.set("param", String.format("{\"sex\":1,\"headId\":\"106000\",\"nickName\":\"%s\",\"userId\":%d,\"osVersion\":\"\",\"appVersion\":\"4.7.2\",\"costumeId\":106200}", nickname, this.userId));
                    return this.httpClient.post(this.port, this.host, "/Web/createRole")
                            .sendForm(createRoleForm);
                })
                .onSuccess(r -> {
                    JsonObject bodyAsJsonObject = r.bodyAsJsonObject();
                    promise.complete(bodyAsJsonObject);
                });
        return promise.future();
    }


    public Future<Object> createWebsocketClient() {
        HttpClientOptions httpClientOptions = new HttpClientOptions()
                .setKeepAlive(true)
                .setMaxWebSocketFrameSize(65535 * 10);
        HttpClient client = this.vertx.createHttpClient(httpClientOptions);
        Promise<Object> promise = Promise.promise();
        WebSocketConnectOptions webSocketConnectOptions = new WebSocketConnectOptions()
                .setHost(this.wsHost)
                .setPort(this.wsPort)
                .setTimeout(1000);
        client.webSocket(webSocketConnectOptions, res -> {
            if (res.succeeded()) {
                this.websocketConn = res.result();
                promise.complete();
            }
            if (res.failed()) {
                System.out.println("Connect failed");
            }
        });

        promise.future().onSuccess(o -> {
            LoginProto.LoginReqMsg.Builder builder = LoginProto.LoginReqMsg.newBuilder();
            builder.setLangType("zh_tw");
            builder.setOpenId(this.openId);
            builder.setUserId(this.userId);
            YanQuMessage yanQuMessage = YanQuMessageUtils.buildMessage(AgentProtocol.A_LOGIN_REQUEST, builder);
            yanQuMessage.setPlayerId(this.userId);
            Encrypt encrypt = new Encrypt();
            Buffer buffer = encrypt.encodeYanquMessage(yanQuMessage);
            this.websocketConn.writeBinaryMessage(buffer);
        });


        Promise<Object> websocketLogin = Promise.promise();

        promise.future().onSuccess(o -> {
            vertx.setPeriodic(5000, id -> {
                YanQuMessage yanQuMessage = YanQuMessageUtils.buildMessage(GameProtocol.S_PLAYER_PING);
                yanQuMessage.setPlayerId(this.userId);
                Encrypt encrypt = new Encrypt();
                Buffer buffer = encrypt.encodeYanquMessage(yanQuMessage);
                this.websocketConn.writeBinaryMessage(buffer);
            });
            this.websocketConn.closeHandler(h -> {
                System.out.println("closeHandler");
                System.out.println(h);
            });
            this.websocketConn.frameHandler(webSocketFrame -> {
                System.out.println("frameHandler");
                System.out.println(webSocketFrame);
                Buffer buffer = webSocketFrame.binaryData();
                Decrypt decrypt = new Decrypt();
                YanQuMessage yanQuMessage = decrypt.decodeYanquMessage(buffer);
                System.out.println(yanQuMessage);
                if (yanQuMessage.getCode() == 101) {
                    websocketLogin.complete();
                }
            });
            this.websocketConn.exceptionHandler(h -> {
                System.out.println("exceptionHandler");
            });
        });
        return websocketLogin.future();
    }

    public void sendMessage(YanQuMessage yanQuMessage) {
        Encrypt encrypt = new Encrypt();
        Buffer buffer = encrypt.encodeYanquMessage(yanQuMessage);
        this.websocketConn.writeBinaryMessage(buffer);
    }

    public long getUserId() {
        return userId;
    }

    public void setUserId(long userId) {
        this.userId = userId;
    }
}
